package org.finesys.common.security.authentication.handler;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.RequiredArgsConstructor;
import org.finesys.common.core.module.R;
import org.finesys.common.core.util.AsyncUtil;
import org.finesys.system.api.entity.SysLog;
import org.finesys.system.api.feign.LogServiceApi;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 认证失败返回
 */
public class AuthAuthenticationFailureHandler implements AuthenticationFailureHandler {


    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        AsyncUtil.parallel(true, new AuthAuthenticationFailureLog(request, exception), new AuthAuthenticationFailureResponse(response, exception));
    }

    @RequiredArgsConstructor
    public class AuthAuthenticationFailureLog implements Runnable {
        private final HttpServletRequest request;
        private final AuthenticationException authenticationException;

        @Override
        public void run() {
            //请求信息不能为空
            if (request == null) {
                return;
            }
            String userName = request.getParameter(OAuth2ParameterNames.USERNAME);
            SysLog logDto = new SysLog();
            logDto.setTitle(String.format("用户[%s]登录失败%s", userName, authenticationException.getMessage()));
            logDto.setUserAgent(userName);
            logDto.setCreateBy(userName);
            logDto.setRemoteAddr(ServletUtil.getClientIP(request));
            logDto.setRequestUri(request.getRequestURI());
            logDto.setParamsData(userName);
            logDto.setLogType(4);
            logDto.setMethod(request.getMethod());
            LogServiceApi logServiceApi = SpringUtil.getBean(LogServiceApi.class);
            logServiceApi.add(logDto);
        }
    }

    @RequiredArgsConstructor
    public class AuthAuthenticationFailureResponse implements Runnable {
        private final HttpServletResponse response;
        private final AuthenticationException authenticationException;
        private final MappingJackson2HttpMessageConverter errorHttpResponseConverter = new MappingJackson2HttpMessageConverter();

        @Override
        public void run() {
            ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
            httpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
            String errorMsg = "";
            if (authenticationException instanceof OAuth2AuthenticationException) {
                OAuth2AuthenticationException oAuth2AuthenticationException = (OAuth2AuthenticationException) authenticationException;
                errorMsg = StrUtil.isBlank(oAuth2AuthenticationException.getError().getDescription()) ? oAuth2AuthenticationException.getError().getErrorCode() : oAuth2AuthenticationException.getError().getDescription();

            } else {
                errorMsg = authenticationException.getLocalizedMessage();
            }
            try {
                this.errorHttpResponseConverter.write(R.failed(errorMsg), MediaType.APPLICATION_JSON, httpResponse);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
